﻿using System;
using System.Collections.Generic;
#if DEBUG
using System.Diagnostics;
#endif // #if DEBUG
using System.Linq;
using System.Text;
using System.Threading;

using FRL.DebtChased.Repository;
using FRL.DebtChased.ServiceUtilities;

namespace FRL.DebtChased.ClockworkService
{

	/// <summary>
	/// Declaration of BaseWorker class
	/// </summary>
	abstract class BaseWorker
	{

		/////////////////////////////////////////////////////////////
		// Deletages

		protected delegate void WorkerFunctionDelegate(object ob);

		/////////////////////////////////////////////////////////////
		// Constants

		private const int SHORT_WAIT_TICKS = 5 * 1000;
		private const int LONG_WAIT_TICKS = 30 * 1000;

		/////////////////////////////////////////////////////////////
		// Attributes

		protected Thread m_workerThread = null;
		protected ManualResetEvent m_eventKill = new ManualResetEvent(false);
		protected ManualResetEvent m_eventDead = new ManualResetEvent(false);

		public bool IsBusy
		{
			get { return ((m_workerThread != null) && (!m_eventDead.WaitOne(0))); }
		}

		/////////////////////////////////////////////////////////////
		// Construction

		/////////////////////////////////////////////////////////////
		// Implementation

		protected abstract string ThreadName
		{
			get;
		}

		protected abstract bool _doWork();

		/////////////////////////////////////////////////////////////
		// Operations - Start and stop

		public void Start()
		{

			// Update log file
			_appendToLog("Starting");

			// Start the worker thread
			m_eventKill.Reset();
			m_eventDead.Reset();
			m_workerThread = new Thread(new ParameterizedThreadStart(_fnWorker));
			m_workerThread.Start(this);

		}

		public void Stop()
		{

			// Update log file
			_appendToLog("Stopping");

			// Kill the thread
			m_eventKill.Set();

			// Wait for dead
			m_eventDead.WaitOne();

			// Update log file
			_appendToLog("Stopped");

			// Thread is dead
			m_workerThread = null;

		}

		/////////////////////////////////////////////////////////////
		// Worker function

		private void _fnWorker(object ob)
		{

			// Declaration of local variables
			int iWaitTicks = 0;

			// Update log file
			_appendToLog("Started");

			// wait for kill
			while (!m_eventKill.WaitOne(iWaitTicks))
			{

				// Call the processing function
				bool bIsWorkDone = _doWork();

				// Recalc the wait ticks
				iWaitTicks = bIsWorkDone ? SHORT_WAIT_TICKS : LONG_WAIT_TICKS;

			} // while-loop

			// Update log file
			_appendToLog("Exiting");

			// Update dead event
			m_eventDead.Set();

		}

		/////////////////////////////////////////////////////////////
		// Operations

		protected void _appendToLog(string strMsg)
		{

			// Prefix message with thread name
			LogFile.Append(string.Format("{0}: {1}", ThreadName, strMsg));

		}

	}

}
